/*
	Copyright (c) 2010 <copyright holders>
	This source code is licensed under The MIT License,
	see the file LICENSE for details.
	*/

#include "WorldPresentation.hpp"

#include <OGRE/OgreRoot.h>
#include <OGRE/OgreRenderWindow.h>
#include <QuickGUIKeyCode.h>
#include <QuickGUIManager.h>
#include <QuickGUIMouseButtonID.h>

#include "CameraMan.hpp"
#include "FixedTerrainHeader.hpp"
#include "Game.hpp"
#include "WorldInputHandler.hpp"
#include "WorldGUI.hpp"
#include "WorldScene.hpp"
#include "WorldManager.hpp" //TODO: remove when possible

namespace spelprog2 {
namespace presentation {

WorldPresentation::WorldPresentation(Game & game, sim::Int seed, const std::string & scenarioName) : Presentation(game),
    type_(WP_PLAY),
    seed_(seed),
    name_(scenarioName),
    sceneMan_(dynamic_cast<Ogre::TerrainSceneManager *>(game.getRoot().createSceneManager("TerrainSceneManager"))),
    scene_(new WorldScene(game.getWorldManager(), *sceneMan_)),
    inputHandler_(new WorldInputHandler(game, *scene_)),
    gui_(),
    moveCam_(false),
    mouseInWorld_(false)
{
}

WorldPresentation::WorldPresentation(Game & game, const std::string & replayName) : Presentation(game),
    type_(WP_REPLAY),
    name_(replayName),
    sceneMan_(dynamic_cast<Ogre::TerrainSceneManager *>(game.getRoot().createSceneManager("TerrainSceneManager"))),
    scene_(new WorldScene(game.getWorldManager(), *sceneMan_)),
    inputHandler_(new WorldInputHandler(game, *scene_)),
    gui_(),
    moveCam_(false),
    mouseInWorld_(false)
{
}

WorldPresentation::~WorldPresentation()
{
    delete scene_; //must be done first
    gui_.reset();
    getGame().getRoot().destroySceneManager(sceneMan_);
}

void WorldPresentation::initScene()
{
    if (type_ == WP_PLAY) {
        //TODO: make playerId assignable in GUI rather than deriving it from join order (this also leads to out of bounds errors under many conditions)
        net::UserId clientId = getGame().getNetworking().getMyClientId();
        sim::Int playerId = boost::lexical_cast<int>(getGame().getNetworking().getVars().getVar(clientId, "player"));
        getGame().getWorldManager().startBattle(seed_, name_, playerId);
    }
    else if (type_ == WP_REPLAY) {
        getGame().getWorldManager().startReplay(name_);
    }
}

void WorldPresentation::initCameraManager()
{
    int width = Ogre::Root::getSingletonPtr()->getAutoCreatedWindow()->getWidth(),
        height = Ogre::Root::getSingletonPtr()->getAutoCreatedWindow()->getHeight();
    cameraMan_.reset(new CameraMan(getGame().getCamera(), getGame().getWorldManager().getLandscape(), width, height));
	cameraMan_->updateCamera();
}

void WorldPresentation::initGUI()
{
    gui_.reset(new gui::WorldGUI(getGame(), *sceneMan_, *scene_));
}

void WorldPresentation::update(float deltaTime)
{
    scene_->gfxUpdate(deltaTime);
}

void WorldPresentation::keyPressed(const OIS::KeyEvent & ev)
{
    const bool handled1 = gui_->getManager().injectKeyDown(QuickGUI::KeyCode(ev.key));
    const bool handled2 = gui_->getManager().injectChar(ev.text);
    if (!(handled1 || handled2)) {
        cameraMan_->injectKeyDown(ev);
    }
}

void WorldPresentation::keyReleased(const OIS::KeyEvent & ev)
{
    if (!gui_->getManager().injectKeyUp(QuickGUI::KeyCode(ev.key))) {
        cameraMan_->injectKeyUp(ev);
    }
}

void WorldPresentation::mouseMoved(const Ogre::Vector2 & point, const Ogre::Vector2 & normalizedPoint,
    const OIS::MouseEvent & ev)
{
    if (moveCam_) {
        cameraMan_->injectMouseMove(ev);
    }
    else if (mouseInWorld_) {
        inputHandler_->injectMouseMove(normalizedPoint.x, normalizedPoint.y);
    }
    else if (!gui_->getManager().injectMousePosition(int(point.x), int(point.y))) {
        inputHandler_->injectMouseMove(normalizedPoint.x, normalizedPoint.y);
    }
    
    cameraMan_->injectMouseMove(ev, true);
}

void WorldPresentation::mousePressed(const Ogre::Vector2 & point, const Ogre::Vector2 & normalizedPoint,
    const OIS::MouseEvent & ev, OIS::MouseButtonID id)
{
    mouseInWorld_ = false;

    if (id == OIS::MB_Middle) { //TODO: add check to be in play mode
        moveCam_ = true;
        cameraMan_->injectMouseDown(ev, id);
    }
    else if (!gui_->getManager().injectMouseButtonDown(QuickGUI::MouseButtonID(id))) {
        inputHandler_->injectMouseDown(normalizedPoint.x, normalizedPoint.y, id);
        mouseInWorld_ = true;
    }
}

void WorldPresentation::mouseReleased(const Ogre::Vector2 & point, const Ogre::Vector2 & normalizedPoint,
    const OIS::MouseEvent & ev, OIS::MouseButtonID id)
{
    if (moveCam_) {
        moveCam_ = false;
		//cameraMan_->resetCamera();
        cameraMan_->injectMouseUp(ev, id);
        cameraMan_->manualStop();
    }
    else {
        if (!gui_->getManager().injectMouseButtonUp(QuickGUI::MouseButtonID(id)) && mouseInWorld_) {
            inputHandler_->injectMouseUp(normalizedPoint.x, normalizedPoint.y, id);
        }
    }

    if (mouseInWorld_) {
        inputHandler_->lostMouseUp();
        mouseInWorld_ = false;
    }
}

}; //presentation
}; //spelprog
